package org.springframework.boot.netty.argumentResolver;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.netty.annotation.Injected;
import org.springframework.boot.netty.exception.ConvertException;
import org.springframework.boot.netty.listener.Message;
import org.springframework.context.annotation.Bean;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Array;
import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Author: huoxingzhi
 * Date: 2020/12/16
 * Email: hxz_798561819@163.com
 */
public class BeanAwareMethodArgumentResolver extends HandlerMethodArgumentResolverAdapter {

    @Override
    public boolean supportsParameter(Class<?> receiveClass,MethodParameter methodParameter) {
        Autowired autowired = methodParameter.getParameter().getAnnotation(Autowired.class);
        Injected injected = methodParameter.getParameter().getAnnotation(Injected.class);
        return !ObjectUtils.isEmpty(injected) || !ObjectUtils.isEmpty(autowired);
    }

    @Override
    public Object resolveArgument(Message message, MethodParameter methodParameter) throws ConvertException {

        Parameter parameter = methodParameter.getParameter();
        Type parameterType = parameter.getParameterizedType();
        Type[] actualTypeArgument = new Type[2];
        // map or list 处理
        if(parameterType instanceof ParameterizedType) {
            Type[] types = ((ParameterizedType) parameterType).getActualTypeArguments();
            if(types.length==1){
                actualTypeArgument[0] = String.class;
                actualTypeArgument[1] = types[0];
            }else {
                actualTypeArgument = types;
            }
        }

        if(((Class)parameterType).isArray()){
            // 对象数组处理
            actualTypeArgument[0] = String.class;
            actualTypeArgument[1] = ((Class)parameterType).getComponentType();
        }else {
            // 普通对象处理
            actualTypeArgument[0] = String.class;
            actualTypeArgument[1] = parameterType;
        }

        if(!String.class.isAssignableFrom((Class<?>) actualTypeArgument[0])){
            throw new ConvertException(getClass()+" Map类型第一个泛型必须为String");
        }

        Map<String, ?> beansOfType = this.applicationContext.getBeansOfType((Class<?>) actualTypeArgument[1]);

        if(List.class.isAssignableFrom(parameter.getType())){
            return beansOfType.values().stream().collect(Collectors.toList());
        }

        if (parameter.getType().isArray()){
            Object[] objects = beansOfType.values().toArray();
            Object o = Array.newInstance((Class<?>) actualTypeArgument[1], objects.length);
            for(int i=0; i<objects.length; i++) {
                ((Object[]) o)[i] = objects[i];
            }
            return o;
        }

        if(Map.class.isAssignableFrom(parameter.getType())){
            return beansOfType;
        }

        return beansOfType.values().toArray()[0];

    }
}
